﻿using System;
using System.Collections.Generic;
using System.Linq;

using SharedGenomics.Core;
using SharedGenomics.Annotations;

namespace SharedGenomics.Workbench.Annotations
{
    /// <summary>
    /// An instance of this class provides metadata about a particular annotation type in the system
    /// </summary>
    public class AnnotationDescriptor
    {
        private static IDictionary<AnnotationKey, AnnotationDescriptor> _keyDescriptorMap;

        static AnnotationDescriptor()
        {
            var descriptors = new List<AnnotationDescriptor>
            {
                CreateDescriptorFor<GeneSummaryAnnotation>("Gene summary", "Contains a summary of gene information", false, AnnotationKey.Gene),
                CreateDescriptorFor<GoogleSearchAnnotation>("Google search", "Performs a google search for a SNP by name", false, AnnotationKey.GoogleSearch),
                CreateDescriptorFor<KeggPathwayAnnotation>("Kegg pathway(s)", "Contains all the Kegg Pathways a gene is involved in", false, AnnotationKey.KeggPathway),
                CreateDescriptorFor<NcbiAnnotation>("Ncbi summary", "Contains a brief summary of SNP information from the NCBI", false, AnnotationKey.NcbiSummary),
                CreateDescriptorFor<PublicationsAnnotation>("Publications", "Contains a small selection of publications relating to the gene", false, AnnotationKey.Publications),
                CreateDescriptorFor<PubMedSearchAnnotation>("PubMed search", "Performs a PubMed search for the gene", false, AnnotationKey.PubMedSearch)
                //CreateDescriptorFor<UcscBrowserAnnotation>("UCSC browser", "Opens the UCSC browser for the SNP", false, AnnotationKey.UcscBrowser)
            };

            _keyDescriptorMap = descriptors.ToDictionary(ad => ad.Key, ad => ad);
        }

        private AnnotationDescriptor(Type annotationType, string name, string description, bool isInternal, AnnotationKey key)
        {
            //NOTE: the following two checks should never fail since descriptor is created by factory method
            annotationType.ThrowIfNull("annotationType");
            ExceptionHelper.ThrowIf<ArgumentException>(!typeof(IAnnotation).IsAssignableFrom(annotationType));

            name.ThrowIfNull("name");
            description.ThrowIfNull("description");
            key.ThrowIfNull("key");

            this.AnnotationType = annotationType;
            this.Name = name;
            this.Description = description;
            this.IsInternal = isInternal;
            this.Key = key;
        }

        public Type AnnotationType { get; private set; }
        public string Name { get; private set; }
        public string Description { get; private set; }
        public bool IsInternal { get; private set; }
        public AnnotationKey Key { get; private set; }

        private static AnnotationDescriptor CreateDescriptorFor<T>(string name, string description, bool isInternal, AnnotationKey key) where T : IAnnotation
        {
            return new AnnotationDescriptor(typeof(T), name, description, isInternal, key);
        }

        //TODO: This may have to be changed to a more flexible method of obtaining all annotations in the system in future if users can define their own
        public static IEnumerable<AnnotationDescriptor> AllAnnotationDescriptors
        {
            get
            {
                return _keyDescriptorMap.Values;
            }
        }

        public static AnnotationDescriptor GetDescriptorForKey(AnnotationKey key)
        {
            key.ThrowIfNull("key");
            ExceptionHelper.ThrowIf<ArgumentException>(!_keyDescriptorMap.ContainsKey(key), String.Format("No descriptor found for key {0}", key.Key));

            return _keyDescriptorMap[key];
        }
    }
}
